package com.learning.thread.juc.callable;

import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * ClassName: CallableFirst
 * Description: 有返回的线程
 * Date: 2016/11/26 17:45
 *
 * @author SAM SHO
 * @version V1.0
 */
public class CallableFirst {

    /**
     * 提交一个Callable
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    void test1() throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        // 提交一个 Callable
        Future<String> future = executor.submit(new InCallableTask());

        System.out.println(future.isDone());

        // 会一直阻塞, 直到任务完成，结果返回
        System.out.println(future.get());
    }

    /**
     * 利用 FutureTask 实现提交一个任务
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    void test2() throws ExecutionException, InterruptedException {
        // Callable 任务使用 FutureTask 封装
        FutureTask<String> future = new FutureTask<>(new InCallableTask());
        ExecutorService executor = Executors.newFixedThreadPool(1);
        // 提交 FutureTask , 因为FutureTask 实现了 Runnable, Future 接口
        executor.submit(future);

        // 会一直阻塞, 直到任务完成，结果返回
        System.out.println("返回的数据： " + future.get());

        executor.shutdown();
    }

    /**
     * 提交多个任务，任务谁先完成就先返回
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    void test3() throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 一般使用需要构建多个 FutureTask 对象
        FutureTask<String> future = new FutureTask<>(new InCallableTask());
        FutureTask<String> futureLongTime = new FutureTask<>(new InCallableTaskLongTime());

        // 提交两个任务
        executor.submit(future);
        executor.submit(futureLongTime);

        System.out.println("干其他事情去吧..........");

        System.out.println(future.get());
        System.out.println(futureLongTime.get());

        executor.shutdown();
    }

    /**
     * 提交一组任务
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    void test4() throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(1);

        List<Callable<String>> list = new ArrayList<>(2);
        list.add(new InCallableTask());
        list.add(new InCallableTaskLongTime());

        // 需要所有的任务完成后才返回
        // 两个任务都完成后一起返回，会等待最慢的那个任务完成后一起返回
        List<Future<String>> futures = executor.invokeAll(list);
        for (Future<String> future : futures) {
            System.out.println(future.get());
        }

        // 返回最先完成的那个任务，未执行的任务都会被取消
        String result = executor.invokeAny(list);
        System.out.println(result);
    }


    /**
     * 使用 ExecutorCompletionService 提交一组任务
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    void test5() throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        // 创建 ExecutorCompletionService 类，内部使用 LinkedBlockingQueue 存放 Future，可以手动指定任务个数
        ExecutorCompletionService<String> ecs = new ExecutorCompletionService<>(executor);

        // 任务列表
        ArrayList<Callable<String>> tasks = Lists.newArrayList(new InCallableTask(), new InCallableTaskLongTime());

        List<Future<String>> futures = new ArrayList<>();

        // 提交一组任务
        for (Callable<String> callable : tasks) {
            Future<String> future = ecs.submit(callable);
            // 这边可以
            futures.add(future);
        }

        // 获取任务结果: 内部使用 BlockingQueue 存放 Future, 先完成的先返回
        for (int i = 0; i < tasks.size(); i++) {
            System.out.println(ecs.take().get());
        }

        // 这边应该在 finally 中处理
        for (Future<String> future : futures) {
            future.cancel(true);
        }

        executor.shutdown();
    }

    /**
     * 自定义任务
     */
    class InCallableTask implements Callable<String> {
        @Override
        public String call() throws Exception {
            Thread.sleep(1000L);
            return "Hello SAM !! " + Thread.currentThread().getName();
        }
    }

    class InCallableTaskLongTime implements Callable<String> {
        @Override
        public String call() throws Exception {
            Thread.sleep(10000L);
            return "Hello SAM, Long Time Task : " + Thread.currentThread().getName();
        }
    }

}
